# -*- coding: utf-8 -*-

# Copyright (c) 2025 Lijiang
# Licensed under the MIT License
# See LICENSE file for details

"""
文件处理工具类
"""

import os
import shutil
import platform
from pathlib import Path
from typing import List, Dict, Optional
from config import SUPPORTED_VIDEO_FORMATS, MAX_FILE_SIZE_BYTES


class FileHandler:
    """文件处理工具类"""
    
    ############################### 支持的视频格式 ###############################
    SUPPORTED_FORMATS = SUPPORTED_VIDEO_FORMATS
    
    @staticmethod
    def get_file_size(file_path: str) -> str:
        """获取文件大小的可读格式"""
        try:
            size_bytes = os.path.getsize(file_path)
            if size_bytes < 1024:
                return f"{size_bytes} B"
            elif size_bytes < 1024 * 1024:
                return f"{size_bytes / 1024:.1f} KB"
            elif size_bytes < 1024 * 1024 * 1024:
                return f"{size_bytes / (1024 * 1024):.1f} MB"
            else:
                return f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"
        except OSError:
            return "未知"
    
    @staticmethod
    def get_file_size_bytes(file_path: str) -> int:
        """获取文件大小的字节数"""
        try:
            return os.path.getsize(file_path)
        except OSError:
            return 0
    
    @staticmethod
    def format_size_bytes(size_bytes: int) -> str:
        """将字节数格式化为可读格式"""
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.1f} KB"
        elif size_bytes < 1024 * 1024 * 1024:
            return f"{size_bytes / (1024 * 1024):.1f} MB"
        else:
            return f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"
    
    @staticmethod
    def estimate_output_size(input_file_path: str, compression_ratio: float) -> str:
        """估算输出文件大小"""
        try:
            ############################### 获取原始文件大小 ###############################
            original_size = FileHandler.get_file_size_bytes(input_file_path)
            if original_size == 0:
                return "未知"
            
            ############################### 计算压缩后的尺寸比例 ###############################
            scale_ratio = 1.0 - compression_ratio
            
            ############################### 估算压缩后的大小（基于尺寸缩放和压缩算法） ###############################
            # 这里使用一个经验公式：文件大小与尺寸的平方成正比，再考虑压缩算法的影响
            size_ratio = scale_ratio ** 2  # 尺寸缩放对文件大小的影响
            
            ############################### 根据压缩比例调整压缩效果 ###############################
            if compression_ratio == 0:
                ############################### 不压缩，保持原大小 ###############################
                estimated_size = original_size
            elif compression_ratio <= 0.3:
                ############################### 轻度压缩，主要靠尺寸缩放 ###############################
                estimated_size = original_size * size_ratio * 0.8
            elif compression_ratio <= 0.6:
                ############################### 中度压缩，尺寸缩放 + 质量压缩 ###############################
                estimated_size = original_size * size_ratio * 0.6
            else:
                ############################### 重度压缩，尺寸缩放 + 强质量压缩 ###############################
                estimated_size = original_size * size_ratio * 0.4
            
            return FileHandler.format_size_bytes(int(estimated_size))
        except Exception:
            return "未知"
    
    @staticmethod
    def is_video_file(file_path: str) -> bool:
        """检查文件是否为支持的视频格式"""
        return Path(file_path).suffix.lower() in FileHandler.SUPPORTED_FORMATS
    
    @staticmethod
    def get_file_info(file_path: str) -> Dict[str, str]:
        """获取文件信息"""
        try:
            path = Path(file_path)
            return {
                'name': path.name,
                'size': FileHandler.get_file_size(file_path),
                'format': path.suffix.upper(),
                'path': str(path.absolute())
            }
        except Exception:
            return {
                'name': '未知文件',
                'size': '未知',
                'format': '未知',
                'path': file_path
            }
    
    @staticmethod
    def generate_output_path(input_path: str, compression_ratio: float) -> str:
        """生成输出文件路径"""
        try:
            path = Path(input_path)
            ############################### 在文件名后添加压缩比例和_compressed后缀 ###############################
            name_parts = path.stem.split('_')
            if name_parts[-1] == 'compressed':
                ############################### 如果已经是压缩文件，替换压缩比例 ###############################
                name_parts[-2] = f"{int(compression_ratio * 100)}"
            else:
                ############################### 添加压缩比例和compressed标识 ###############################
                name_parts.append(f"{int(compression_ratio * 100)}")
                name_parts.append('compressed')
            
            new_name = '_'.join(name_parts) + path.suffix
            return str(path.parent / new_name)
        except Exception:
            ############################### 如果出错，使用默认命名方式 ###############################
            path = Path(input_path)
            return str(path.parent / f"{path.stem}_compressed{path.suffix}")
    
    @staticmethod
    def check_disk_space(file_path: str, required_size: int) -> bool:
        """检查磁盘空间是否足够"""
        try:
            if platform.system() == "Windows":
                ############################### Windows 系统使用 shutil.disk_usage ###############################
                free_space = shutil.disk_usage(os.path.dirname(file_path)).free
                return free_space > required_size
            else:
                ############################### Unix/Linux 系统使用 os.statvfs ###############################
                statvfs = os.statvfs(os.path.dirname(file_path))
                free_space = statvfs.f_frsize * statvfs.f_bavail
                return free_space > required_size
        except (OSError, AttributeError):
            return True  # 如果无法检查，假设空间足够
    
    @staticmethod
    def validate_video_file(file_path: str) -> tuple[bool, str]:
        """验证视频文件是否有效"""
        try:
            if not os.path.exists(file_path):
                return False, "文件不存在"
            
            if not FileHandler.is_video_file(file_path):
                return False, "不支持的视频格式"
            
            ############################### 检查文件大小 ###############################
            file_size = os.path.getsize(file_path)
            if file_size == 0:
                return False, "文件为空"
            
            if file_size > MAX_FILE_SIZE_BYTES:
                from config import get_error_message
                return False, get_error_message("file_too_large")
            
            return True, "文件有效"
        except Exception as e:
            return False, f"文件验证失败: {str(e)}"
    
    @staticmethod
    def cleanup_temp_files(temp_files: List[str]) -> None:
        """清理临时文件"""
        for temp_file in temp_files:
            try:
                if os.path.exists(temp_file):
                    os.remove(temp_file)
            except Exception:
                pass  # 忽略清理错误
